//define macro listed below
//
//#define __StrChkPermission(stream)
//#define __StrChgPermission(originStream,stream)
//#define __StrDelPermission(stream)
//#define __GetNextBlk(stream)
//#define __SetNextBlk(stream,aftstream)
//#define __BlkStateAddr(stream)
//#define __BlkWrittenAmount(stream)
//#define __BlkOpAddr(stream)
//#define __BlkAddOpAddr(stream,num)

//#define blkSize
//#define strType
//#define blkAlign
#ifdef strType



#define __DEFAULT__PUBLIC__STRTYPE  _str
#define _dfps  __DEFAULT__PUBLIC__STRTYPE


#define MAPPED_STREAM 

//#include "length.h"
#define _length  unsigned int
//_length is basic type to measure the length or offset, it's customized -- but you should give a way to compare
//in the length.h there is a type __LENGTH used as the specfic size

#define UNLIMITED 0
//ONLY used in num/size

#include "model_Stream_IO.h"
#include <OSProc.h>
//#define _STRFUNC(funcName)              strType##_##funcName
//using CPP-- the redifinated function
#define _STRFUNC(funcName)              funcName
#define STRFUNC(funcName) 	        _STRFUNC(funcName)




//extern strType STRFUNC(CreateStream) ();
//extern strType STRFUNC(CreateStreamBlock) (strType stream);

strType STRFUNC(CreateStream)(strType (*allocMemory)(_ptlong))
{
  return _CreateStream(allocMemory);
}

static strType STRFUNC(CreateStreamBlock)(strType stream)
{
  return _CreateStreamBlock(stream);
}


int STRFUNC(ConvertToPub) (strType from, _dfps to, _length num, _length offset)
{
  return _ConvertToPub(from,to);
}

int STRFUNC(ConvertToPrv) (_dfps from, strType to, _length num, _length offset)
{
  return _ConvertToPrv(from,to);
}


#define __MCPY_FROMCIRCLE			0
#define __MCPY_TOCIRCLE				1
#define __MCPY_ALLCIRCLE			2

#define __Memcpy_circle(from, to, num, align, ARGUMENT) do\
{															\
	unsigned int i = 0;										\
	for(; i < num ; i ++){\
	if(ARGUMENT == __MCPY_TOCIRCLE)\
	{\
	*((u8*)(((((u32)to) + i) & LOWB(align)) |(((u32)to) & HIGHB(32 - align))))  = *(from + i);\
	}\
	else if(ARGUMENT == __MCPY_FROMCIRCLE)\
	{\
	*(to + i) = *((u8*)(((((u32)from) + i) & LOWB(align)) |(((u32)from) & HIGHB(32 - align))));  \
	}\
	else if(ARGUMENT == __MCPY_ALLCIRCLE)\
	{\
	*((u8*)(((((u32)to) + i) & LOWB(align)) |(((u32)to) & HIGHB(32 - align)))) \
	 = *((u8*)(((((u32)from) + i) & LOWB(align)) |(((u32)from) & HIGHB(32 - align))));\
	}\
	else\
	{\
		break;\
	}\
}while(0);

#ifndef WriteStreamBlock
#define WriteStreamBlock _WriteStreamBlock
inline static strType (_WriteStreamBlock)(strType stream, u8* input, _length num, _length offset)
{//4B Align
	unsigned int algnum = ((num % 4 == 0)?num:(num + (4 - (num%4))));
	u8* opaddr = __BlkOpAddr(stream);
		__Memcpy_circle(input,opaddr,num,blkAlign,__MCPY_TOCIRCLE);
	stream = __BlkAddOpAddr(stream,algnum);
	if(WRITTEN_AMOUNT(stream) + algnum >= blkSize)
		__BlkState(stream) |= IS_FULL;
	return stream;
}

#endif

#ifndef ReadStreamBlock
#define ReadStreamBlock _ReadStreamBlock
inline static strType (_ReadStreamBlock) (strType stream, u8* output, _length num, _length offset)
{//4B Align
	unsigned int algnum = ((num % 4 == 0)?num:(num + (4 - (num%4))));
	u8* opaddr = __BlkOpAddr(stream);
		__Memcpy_circle(opaddr,output,num,blkAlign,__MCPY_FROMCIRCLE);
	stream = __BlkAddOpAddr(stream,algnum);
	return stream;
}

#endif

strType STRFUNC(WriteStream) (strType stream, u8* input, _length num, _length offset)
{
	if(!__StrChkPermission(stream))
		return stream;
	if(__BlkState(stream) & IS_END)
		return stream;
	
	stream = __GetLaskBlk(stream);
	unsigned int state = _BlkState(stream);
	
	while(WRITTEN_AMOUNT(state) + num > blkSize)
	{//Write Apart two blocks
			unsigned int nowblockwrite = blkSize - WRITTEN_AMOUNT(state);
		stream = (WriteStreamBlock)(stream,input,num);
			input += nowblockwrite;
			num -= nowblockwrite;
//		__BlkState(stream) |= IS_FULL;
		stream = STRFUNC(CreateStreamBlock) (stream);
	}

		unsigned int nowblockwrite = num;
	stream = (WriteStreamBlock)(stream,input,nowblockwrite);
	SET_STREAM_WRITTEN_AMOUNT(stream,WRITTEN_AMOUNT(state) + nowblockwrite);

	return stream;
}

strType STRFUNC(ReadStream)  (strType stream, u8* output, _length num, _length offset)
{
//MutiStream is not permitted to have the circle buffer. 
//By not allowing the Reader to change the remainder to do this.
	if(!__StrChkPermission(stream))
		return stream;

	unsigned int state ;
	strType originStream = stream;
	
	while(num > 0)
	{
		state = __BlkState(stream);
		unsigned int written_amount;
		if(state & IS_STREAM)
		written_amount = (state & IS_FULL?blkSize:WRITTEN_AMOUNT(state));
		else
		written_amount = ((state & IS_FULL?blkSize:WRITING_POINT(state)) - (READING_POINT(stream)));

		if(written_amount == 0 && (!(state & IS_JUMPING)))
			break;
		if(written_amount == 0 && (state & IS_END))
		{
			__StrDelPermission(stream);		
			break;
		}
		if(written_amount >= num)
		{
			stream = (ReadStreamBlock)(stream,output,num);
			//Change Written Amount if Stream
			if(state & IS_STREAM)
			{
				if((state & IS_FULL) && (state & IS_JUMPING))
				{
					unsigned int jump_to = JUMPING_TO(state);
					__BlkState(stream) &= ~IS_FULL;	
					SET_STREAM_WRITTEN_AMOUNT(stream,written_amount - num);	
					__SetNextBlk(stream,jump_to);
				}
				else	
				{
					SET_STREAM_WRITTEN_AMOUNT(stream,written_amount - num);	
					__BlkState(stream) &= ~IS_FULL;					
				}

			}
			num = 0;
			break;
		}
		else
		{	
			if(written_amount != 0)
				stream = (ReadStreamBlock)(stream,output,written_amount);
			//Abounden Old Stream Blk & Move to the next one
			if(state & IS_JUMPING)
			{
				strType nextstream = _GetNextBlk(stream);
				NOW_READING_MINUS(stream);
				stream = nextstream;
			}	
			num -= written_amount;
			output += written_amount;
		}		
	}

	__StrChgPermission(originStream,stream);
	return stream;
}

strType STRFUNC(PeekStream)  (strType stream, u32* output, _length num, _length offset)
{
	if(!__StrChkPermission(stream))
		return stream;

	unsigned int state ;
	strType originStream = stream;
	
	while(num > 0)
	{
		state = __BlkState(stream);
		unsigned int written_amount;
		if(state & IS_STREAM)
			written_amount = (state & IS_FULL?blkSize:WRITTEN_AMOUNT(state));
		else
			written_amount = ((state & IS_FULL?blkSize:WRITING_POINT(state)) - (READING_POINT(stream)));

		if(written_amount == 0 && (!(state & IS_JUMPING)))
			break;
		if(written_amount == 0 && (state & IS_END))	
			break;

		if(written_amount >= num)
		{
			stream = STRFUNC(ReadSingleStream)(stream,output,num);
			num = 0;
			break;
		}
		else
		{	
			if(written_amount != 0)
				stream = STRFUNC(ReadSingleStream)(stream,output,written_amount);
			//Abounden Old Stream Blk & Move to the next one
			if(state & IS_JUMPING)
			{
				stream = _GetNextBlk(stream);
			}	
			num -= written_amount;
			output += written_amount;
		}		
	}


	return originStream;
}

strType STRFUNC(SeekStream)  (strType stream, _length num) //need change. should be whatever happend make operating point move 'num'.
//focus on allocate new stream address.
{
	if(!__StrChkPermission(stream))
		return stream;

	unsigned int state ;
	
	while(num > 0)
	{
		state = __BlkState(stream);
		unsigned int written_amount;
		if(state & IS_STREAM)
			written_amount = (state & IS_FULL?blkSize:WRITTEN_AMOUNT(state));
		else
			written_amount = ((state & IS_FULL?blkSize:WRITING_POINT(state)) - (READING_POINT(stream)));

		if(written_amount == 0 && (!(state & IS_JUMPING)))
			break;
		if(written_amount == 0 && (state & IS_END))	
			break;

		if(written_amount + num > blkSize)
		{
			stream = __GetNextBlk(stream);
			num -= (blkSize - written_amount);
		}
		else
		{
			stream = __BlkAddOpAddr(stream,num);
		}
	}
	while(num > 0)
	  {
	    
	  }

	return stream;
}

int STRFUNC(CombineStream)(strType to, strType from)
{
  return _CombineStream(to,from);
}

int STRFUNC(ApartStream)(strType from, strType to, _length partpoint)
{
  return _ApartStream(from, to, partpoint);
}


int STRFUNC(EndStream)(strType target)
{
  return _EndStream(target);
}


#define __ConnectStreamToThread(fromStream,tth)	do\
{							\
	slnode* newnode = _KHEAPAPPLY(sizeof(slnode));	\
	MakeSListNode(newnode,fromStream);		\
	if(tth->streams == NULL)			\
		tth->streams = newnode;			\
	else						\
	{						\
		newnode->next = tth->streams->next;	\
		tth->streams->next = newnode;		\
	}						\
}while(0)


strType STRFUNC(AddStreamTo) (strType stream, _tcb* tth)
{
	unsigned int state = __BlkState(stream);
	if((state & IS_STREAM) && (ALL_READING(state) == 1))
		return (strType A);
	((ALL_READING_ADD(stream) == 1)?0:(return (strType A)));
	((NOW_READING_ADD(stream) == 1)?0:(return (strType A)));
	__ConnectStreamToThread(stream,tth);
	return stream;
}

void* STRFUNC(MapStream)(strType stream)
{
  
}

#endif
